package juc.reentrantlock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * 核心设计原理：“许可”：
 *  park方法本质是消费许可，如果没有可消费的许可，那么就阻塞当前线程，一直等待，直到阻塞线程的unpark方法被其他线程调用，然后消费许可，当前线程被唤醒，继续执行。
 *  unpark方法本质是生产许可，一个线程刚创建出来，然后运行，此时是没有许可的，所以unpark方法可以在park方法前调用。下次park方法调用时，直接消费许可，线程不用阻塞等待许可。许可最多只有一个，连续多次调用unpark只能生产一个许可。
 */
public class LockSupportTest {

    private void printA(Thread thread) {
        try {
            TimeUnit.SECONDS.sleep(20);
            System.out.print("A");
            LockSupport.unpark(thread);  // 唤醒指定线程
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void printB(Thread thread) {
        try {
            TimeUnit.SECONDS.sleep(10);
            LockSupport.park();  // 拿到许可
            System.out.print("B");
            LockSupport.unpark(thread);  // 唤醒指定线程
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void printC() {
        try {
            TimeUnit.SECONDS.sleep(5);
            LockSupport.park();  // 拿到许可
            System.out.print("C");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 输出：ABC
        LockSupportTest test = new LockSupportTest();
        Thread threadC = new Thread(test::printC);
        Thread threadB = new Thread(() -> test.printB(threadC));
        Thread threadA = new Thread(() -> test.printA(threadB));
        threadA.start();
        threadB.start();
        threadC.start();
    }

}
